#include<iostream>
#include<unistd.h>
#include<pthread.h>
#include<queue>
#include<vector>
#include<functional>

using namespace std;

//阻塞队列
//T是阻塞队列的数据类型
template<class T>
class BlockQueue
{
public:
    BlockQueue(int capacity)
        :_capacity(capacity)
    {
        pthread_mutex_init(&_mutex,NULL);
        pthread_cond_init(&_consumer,NULL);
        pthread_cond_init(&_producter,NULL);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_consumer);
        pthread_cond_destroy(&_producter);
    }

    void Push(T& data)
    {
        pthread_mutex_lock(&_mutex);
        while(_bq.size()==_capacity)
        {
            pthread_cond_wait(&_producter,&_mutex);
        }
        _bq.push(data);
        pthread_cond_signal(&_consumer);
        pthread_mutex_unlock(&_mutex);
    }

    void Pop(T& data)
    {
        pthread_mutex_lock(&_mutex);
        while(_bq.empty())
        {
            pthread_cond_wait(&_consumer,&_mutex);
        }
        data=_bq.front();
        _bq.pop();
        pthread_cond_signal(&_producter);
        pthread_mutex_unlock(&_mutex);
    }

private:
    queue<T> _bq;
    int _capacity;//阻塞队列容量
    pthread_mutex_t _mutex;
    pthread_cond_t _consumer;
    pthread_cond_t _producter;
};

//对线程进行封装
//T是临界资源的数据类型
template<class T>
class Pthread
{
public:
    Pthread(function<void(T&)> func,T& data,string name)
        :_func(func)
        ,_data(data)
        ,_pthread_name(name)
    {}

    ~Pthread()
    {}

    static void* thread_func(void* arg)
    {
        Pthread<T>* p=reinterpret_cast<Pthread<T>*>(arg);
        cout<<"thread_func p "<<p<<endl;
        p->_func(p->_data);
        return nullptr;
    }

    void Start()
    {
        cout<<"start() this "<<this<<endl;
        if(-1==pthread_create(&_pthread_id,NULL,thread_func,this))
        {
            perror("pthread_create");
            return;
        }
    }

    void Wait()
    {
        pthread_join(_pthread_id,NULL);
    }

    void Detach()
    {
        pthread_detach(_pthread_id);
    }

    string GetPthreadName()
    {
        return _pthread_name;
    }
  
private:
    pthread_t _pthread_id;//线程ID
    string _pthread_name;//线程名
    T& _data;//临界资源
    function<void(T&)> _func;//线程执行的函数
};


void Product(BlockQueue<int>& bq)
{
    while(true)
    {
        int data=rand()%100;
        bq.Push(data);
        cout<<"producter: "<<pthread_self()<<" product:"<<data<<endl;
        sleep(1);
    }
}

void Consume(BlockQueue<int>& bq)
{
    while(true)
    {
        int data=0;
        bq.Pop(data);
        cout<<"consumer: "<<pthread_self()<<" consume:"<<data<<endl;
        sleep(1);
    }
}

void StartProduct(vector<Pthread<BlockQueue<int>>>& pthreads,BlockQueue<int>& bq,int num)
{
    while(num--)
    {
        pthreads.push_back(Pthread<BlockQueue<int>>(Product,bq,"producter"+to_string(num)));
        pthreads.back().Start();
    }
}

void StartConsume(vector<Pthread<BlockQueue<int>>>& pthreads,BlockQueue<int>& bq,int num)
{
    while(num--)
    {
        pthreads.push_back(Pthread<BlockQueue<int>>(Consume,bq,"consumer"+to_string(num)));
        pthreads.back().Start();
    }
}

void WaitAllPthreads(vector<Pthread<BlockQueue<int>>>& pthreads)
{
    int i=1;
    for(auto& e:pthreads)
    {
        e.Wait();
    }
}

int main()
{
    srand(time(NULL));
    vector<Pthread<BlockQueue<int>>> pthreads;
    BlockQueue<int> bq(1);
    StartProduct(pthreads,bq,1);
    StartConsume(pthreads,bq,1);
    WaitAllPthreads(pthreads);
    return 0;
}